﻿using System;
using System.Net;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Controls;
using System.Collections.Generic;




namespace VAdvantage.DataUtil
{
	public class DataObject : INotifyPropertyChanged, IEditableObject
	{
		protected Dictionary<string, object> _backupData = new Dictionary<string, object>();
        protected Dictionary<string, object> _newRowData = new Dictionary<string, object>();

        public DataObject()
        {
        this.State = DataStates.Added;
        }


		public enum DataStates
		{
			Unchanged = 2,
			Added = 4,
			Deleted = 8,
			Modified = 16,
		} 
		public DataStates State { get; set; }
		public object GetFieldValue(string fieldname)
		{
            if (this.State == DataStates.Added)
                return null;

            object value = null;
			PropertyInfo pi = this.GetType().GetProperty(fieldname);
			if (pi != null)
				 value =  pi.GetValue(this, null);

            if (value != null)
            {
                if(value.Equals(-1) || value.Equals("")) 
                    
                //_newRowData.ContainsKey(fieldname) && _newRowData[fieldname] == null)
               // {
                    value = null;
                //}
            }
			return value;
		}
		public void SetFieldValue(string fieldname, object value, bool initial)
		{
            if (value == DBNull.Value)
            {
                value = null;
            }
            this.State = DataStates.Modified;
			this.SetFieldValue(fieldname, value);
			if (initial)
			{
				this.State = DataStates.Unchanged;
				if (!_backupData.ContainsKey(fieldname))				
					_backupData.Add(fieldname, value);				
			}

		}


        public void SetFieldValue(string fieldname, object value, bool initial,bool newRow)
        {
            if (value == DBNull.Value)
            {
                value = null;
            }
            this.State = DataStates.Modified;
            this.SetFieldValue(fieldname, value);
            if (newRow)
            {
                //this.State = DataStates.Unchanged;
                if (!_newRowData.ContainsKey(fieldname))
                    _newRowData.Add(fieldname, value);
            }

        }


        public void SetBackupData(string fieldname,object data)
        {
            if (!_backupData.ContainsKey(fieldname))
                _backupData.Add(fieldname, data);	
        }

        private bool IsNumber(Type type)
        {
            if (type == typeof(int) || type == typeof(decimal))
            {
                return true;
            }

            return false;
        }

        private bool IsString(Type type)
        {
            if (type == typeof(String)) 
            {
                return true;
            }

            return false;
        }


        private object ConvertToChangeType(object value, Type conversionType, IFormatProvider provider)
        {
            if (conversionType.IsGenericType &&
    conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                {
                    return null;
                } // end if

                // It's a nullable type, and not null, so that means it can be converted to its underlying type,
                // so overwrite the passed-in conversion type with this underlying type
                conversionType = conversionType.GetGenericArguments()[0];
            }
            return Convert.ChangeType(value, conversionType, provider);
        }


		public void SetFieldValue(string fieldname, object value)
		{
			PropertyInfo pi = this.GetType().GetProperty(fieldname);
			if (pi != null)
			{
                object pValue = null;
                try
                {
                    pValue = ConvertToChangeType(value, pi.PropertyType, null);
              
                } 
                catch
                {
                    pValue = null;
                }

                //if (pValue == null)
                //{
                //    if (IsNumber(pi.PropertyType))
                //    {
                //        pValue = -1;
                //    }
                //    else if (IsString(pi.PropertyType))
                //    {
                //        pValue = "";
                //    }

                //}

				//if (pValue != null)
					pi.SetValue(this, pValue, null);									
			}
		}



		public void Delete()
		{
			//this.State = DataStates.Deleted;
		}
		public void NewRow()
		{
			this.State = DataStates.Added;
		}

        

		protected void NotifyChange(params string[] properties)
		{
            if (System.Windows.Deployment.Current.Dispatcher.CheckAccess())
            {
                if (PropertyChanged != null)
                {
                    foreach (string p in properties)
                        PropertyChanged(this, new PropertyChangedEventArgs(p));
                    this.State = DataStates.Modified;
                }
            }
            else
            {
                if (PropertyChanged != null)
                {
                    bool wait = true;


                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            foreach (string p in properties)
                                PropertyChanged(this, new PropertyChangedEventArgs(p));
                            wait = false;
                        });
                    this.State = DataStates.Modified;
                    while (wait)
                    {
                        System.Threading.Thread.Sleep(1);
                    }
                }

            }
			
		}
		#region INotifyPropertyChanged Members
		public event PropertyChangedEventHandler PropertyChanged;
		#endregion

		#region IEditableObject Members

		public void BeginEdit()
		{			
		}

		public void CancelEdit()
		{
			foreach (string fieldName in _backupData.Keys)			
				this.SetFieldValue(fieldName, _backupData[fieldName], true);
            this.State = DataStates.Unchanged;
		}

		public void EndEdit()
		{
            //PropertyInfo[] properties = this.GetType().GetProperties();
            //if (PropertyChanged != null)
            //{
            //    foreach (PropertyInfo p in properties)
            //        PropertyChanged(this, new PropertyChangedEventArgs(p.Name));
            //    //this.State = DataStates.Modified;
            //}
            //this.State = DataStates.Unchanged;
		}

		#endregion

        internal void AcceptChanges()
        {
            if (this.State != DataStates.Unchanged)
            {
                PropertyInfo[] pi = this.GetType().GetProperties();
                if (pi != null)
                {
                    _backupData.Clear();
                    foreach (PropertyInfo prop in pi)
                    {
                        object value = this.GetFieldValue(prop.Name.ToUpper());
                        //_backupData[prop.Name] = value;
                        SetBackupData(prop.Name, value);
                    }
                }
            }
            this.State = DataStates.Unchanged;
            _newRowData.Clear();
        }
    }
}
